﻿package  
{
	import flash.display.MovieClip;
	
	/**
	 * ...
	 * @author Ben Humberston
	 */
	public class Orb extends MovieClip
	{
		public var px:Number; //double precision on the x attribute is a LIE, so we use our own
		public var py:Number; //double precision on the y attribute is a LIE, so we use our own
		public var vx:Number;
		public var vy:Number;
		public var mode:int;
		
		protected var dens:Number;
		protected var rad:Number;
		protected var mass:Number;
		protected var invMass:Number;
		protected var color:uint;
		
		public function get Mass():Number { return mass; } 
		public function get InvMass():Number { return invMass; }
		public function get Radius():Number { return rad; }
		public function get Density():Number { return dens;}
		
		public function Orb(density:Number = 1, radius:Number = 1, color:uint = 0x000000) 
		{
			mode = Groovity.MODE_MATTER;
			px = py = 0;
			vx = vy = 0;
			dens = density; rad = radius;
			this.color = color;
			updateMass();
		}
		
		public function updateMass():void {
			mass = Math.PI * rad * rad * dens;
			invMass = (mass == 0) ? 0 : 1 / mass;
		}
		
		public function draw():void {
			graphics.clear();
			graphics.beginFill(color, 1);
			graphics.drawCircle(0, 0, rad);
			graphics.endFill();
		}
		
		public static function getForceBetween(a:Orb, b:Orb):Vector2 {
			var d:Vector2 = new Vector2(b.px - a.px, b.py - a.py);
			if (d.lenSqrd() == 0) return new Vector2(0,0); //don't even try when two items are colocated
			var mag:Number = (Groovity.G * a.Mass * b.Mass) / d.lenSqrd(); //doesn't work with fixed masses
			mag = Math.min(300, mag); //basic force limiting
			d.normalize();
			d.scale(mag);
			if (a.mode != b.mode && a.mode != Groovity.MODE_OMNIMATTER && b.mode != Groovity.MODE_OMNIMATTER) 
				d.scale( -1); //matter and antimatter repel (ok, not in real life, but in here they do :)
			return d;
		}
		
		/**
		 * Changes the mass of this orb by the given massDelt (positive or negative)
		 * Returns true if the new mass is 0.
		 * @param	massDelt
		 * @return
		 */
		public function changeMass(massDelt:Number):Boolean {
			var newArea:Number = Math.max(0, (this.Mass + massDelt) / Density);
			var newRad:Number = Math.sqrt(newArea / Math.PI);
			rad = newRad;
			updateMass();
			if (newArea == 0) {
				trace("Removed all mass from orb!");
				return true; //we wait until after the radius update in case we keep this around
			}
			return false;
		}
		
		/**
		 * Given an outer circular radius, returns the mass of this orb contained in
		 * a ring section from the outer edge to a paint outerRad towards the center
		 * If outerRad is larger than this orb's radius, returns full orb mass.
		 * @param	outerRad
		 * @return
		 */
		public function getOuterLayerMass(outerRad:Number):Number {
			var innerRad:Number = rad - outerRad;
			if (innerRad <= 0) return Mass;
			var innerMass:Number = Math.PI * innerRad * innerRad * dens;
			return Mass - innerMass;
		}
		
	}
	
}